﻿using MyILog = EasyNet.Componets.Core.Logger.ILog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using System.Threading;
using System.IO;
using log4net.Appender;
using log4net.Core;
using log4net.Config;
using log4net.Filter;

namespace EasyNet.Componets.Logger
{
    public sealed class Log4Logger : MyILog
    {
        private ThreadLocal<Dictionary<Type, ILog>> _threadLocalLogger;


        public Log4Logger()
        {
            log4net.Config.XmlConfigurator.Configure();
        
            _threadLocalLogger = new ThreadLocal<Dictionary<Type, ILog>>
            {
                Value = new Dictionary<Type, ILog>()
            };

        }

        #region 设置默认配置
        static void GetDefualtConfig()
        {
            var appenderList = new RollingFileAppender[4];
            appenderList[0] = GetAppenderConfig(Level.Debug);
            appenderList[1] = GetAppenderConfig(Level.Warn);
            appenderList[2] = GetAppenderConfig(Level.Info);
            appenderList[3] = GetAppenderConfig(Level.Error);
            //appenderList[4] = GetAppenderConfig(Level.Fatal);

            BasicConfigurator.Configure(appenderList);
        }

        private static RollingFileAppender GetAppenderConfig(Level level)
        {
            var appender = new RollingFileAppender
            {
                Name = level.ToString(),
                File = string.Format("Logs\\{0}\\{0}_", level.ToString().ToLower()),
                AppendToFile = true,  //是否在文件中追加
                LockingModel = new FileAppender.MinimalLock(),  //记录日志写入文件时，不锁定文本文件，防止多线程时不能写Log,官方说线程非安全
                RollingStyle = RollingFileAppender.RollingMode.Composite,  //按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])
                DatePattern = "yyyy-MM-dd_HH\".log\"",  //按日期产生文件夹和文件名［在日期方式与混合方式下使用］此处按日期产生文件夹，文件名固定。注意&quot; 的位置
                StaticLogFileName = false,  //是否只写到一个文件中
                Threshold = level,
                MaxSizeRollBackups = -1,  //最多产生的日志文件数，超过则只保留最新的n个。设定值value="－1"为不限文件数
                MaximumFileSize = "5MB",  //最大文件大小
                Layout = new log4net.Layout.PatternLayout("%newline %n%date|%-5level %n%message"),
            };
            appender.ClearFilters();
            appender.AddFilter(new LevelRangeFilter() { LevelMin = level, LevelMax = level });
            appender.ActivateOptions();
            return appender;
        }

        private static ColoredConsoleAppender GetConsoleAppenderConfig()
        {
            var appender = new ColoredConsoleAppender()
            {
                Name = "Console",
                Layout = new log4net.Layout.PatternLayout("%newline %n%date %-5level - %n%message%newline"),
            };
            appender.AddMapping(new ColoredConsoleAppender.LevelColors() { Level = Level.Fatal, BackColor = ColoredConsoleAppender.Colors.White, ForeColor = ColoredConsoleAppender.Colors.Red });
            appender.AddMapping(new ColoredConsoleAppender.LevelColors() { Level = Level.Error, ForeColor = ColoredConsoleAppender.Colors.HighIntensity });
            appender.AddMapping(new ColoredConsoleAppender.LevelColors() { Level = Level.Warn, ForeColor = ColoredConsoleAppender.Colors.Yellow });
            appender.AddMapping(new ColoredConsoleAppender.LevelColors() { Level = Level.Info, ForeColor = ColoredConsoleAppender.Colors.Cyan });
            appender.AddMapping(new ColoredConsoleAppender.LevelColors() { Level = Level.Warn, ForeColor = ColoredConsoleAppender.Colors.Green });

            return appender;
        }
        #endregion

        private ThreadLocal<Dictionary<Type, ILog>> ThreadLocalLogger
        {
            get
            {
                if (_threadLocalLogger == null)
                {
                    _threadLocalLogger = new ThreadLocal<Dictionary<Type, ILog>>
                    {
                        Value = new Dictionary<Type, ILog>()
                    };
                }

                if (_threadLocalLogger.Value == null) _threadLocalLogger.Value = new Dictionary<Type, ILog>();

                return _threadLocalLogger;
            }
        }

        private ILog GetLogger(Type type)
        {
            if (!ThreadLocalLogger.Value.ContainsKey(type))
            {
                ThreadLocalLogger.Value.Add(type, LogManager.GetLogger(type));
            }
            return ThreadLocalLogger.Value[type];
        }


        public void Debug(Type type, string message,
            string memberName = "",
            string sourceFilePath = "",
            int sourceLineNumber = 0)
        {
            if (!String.IsNullOrWhiteSpace(message))
            {
                GetLogger(type).Debug(FormatMessage(message, memberName, sourceFilePath, sourceLineNumber));
            }
        }



        public void Debug(Type type, string message, Exception exception,
            string memberName = "",
            string sourceFilePath = "",
            int sourceLineNumber = 0)
        {
            if (!String.IsNullOrWhiteSpace(message))
            {

                GetLogger(type).Debug(FormatMessage(message, memberName, sourceFilePath, sourceLineNumber), exception);
            }
        }

        public void Debug(Type type, object item,
            string memberName = "",
            string sourceFilePath = "",
            int sourceLineNumber = 0)
        {
            if (item != null)
            {
                GetLogger(type).Debug(FormatMessage(item.ToString(), memberName, sourceFilePath, sourceLineNumber));
            }
        }

        public void LogInfo(Type type, string message,
            string memberName = "",
            string sourceFilePath = "",
            int sourceLineNumber = 0)
        {
            if (!String.IsNullOrWhiteSpace(message))
            {
                GetLogger(type).Info(FormatMessage(message, memberName, sourceFilePath, sourceLineNumber));
            }
        }

        public void LogWarning(Type type, string message,
            string memberName = "",
            string sourceFilePath = "",
            int sourceLineNumber = 0)
        {
            if (!String.IsNullOrWhiteSpace(message))
            {
                GetLogger(type).Warn(FormatMessage(message, memberName, sourceFilePath, sourceLineNumber));
            }
        }

        public void LogError(Type type, string message,
            string memberName = "",
            string sourceFilePath = "",
            int sourceLineNumber = 0)
        {
            if (!String.IsNullOrWhiteSpace(message))
            {
                GetLogger(type).Error(FormatMessage(message, memberName, sourceFilePath, sourceLineNumber));
            }
        }

        public void LogError(Type type, string message, Exception exception,
            string memberName = "",
            string sourceFilePath = "",
            int sourceLineNumber = 0)
        {
            if (!String.IsNullOrWhiteSpace(message)
                &&
                exception != null)
            {
                GetLogger(type).Error(FormatMessage(message, memberName, sourceFilePath, sourceLineNumber), exception);
            }
        }



        public void LogError(Type type, Exception exception,
            string memberName = "",
            string sourceFilePath = "",
            int sourceLineNumber = 0)
        {
            if (exception != null)
            {
                GetLogger(type).Error(FormatMessage("", memberName, sourceFilePath, sourceLineNumber), exception);
            }
        }

        public void Fatal(Type type, string message,
            string memberName = "",
            string sourceFilePath = "",
            int sourceLineNumber = 0)
        {
            if (!String.IsNullOrWhiteSpace(message))
            {

                GetLogger(type).Fatal(FormatMessage(message, memberName, sourceFilePath, sourceLineNumber));
            }
        }

        public void Fatal(Type type, string message, Exception exception,
            string memberName = "",
            string sourceFilePath = "",
            int sourceLineNumber = 0)
        {
            if (!String.IsNullOrWhiteSpace(message)
                &&
                exception != null)
            {

                GetLogger(type).Fatal(FormatMessage(message, memberName, sourceFilePath, sourceLineNumber), exception);
            }
        }

        private string FormatMessage(string message, string memberName, string sourceFilePath, int sourceLineNumber)
        {
            return string.Format(
                "Method: {0}  File: {1} line:{2} Msg: {3}",
                memberName, sourceFilePath, sourceLineNumber, message);
        }

    }
}
